package com.linln.admin.system.service.ql;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.linln.admin.system.service.impl.ScheduleJobDetail;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 一些通用方法的提供
 */
@Slf4j
@Component
public class CommonUtilMethodRuleService implements QlRule {
    @Resource
    private Environment env;
    @Resource
    private ScheduleJobDetail scheduleJobDetail;

    private static final ThreadLocal<String> curToken = new ThreadLocal<>();

    private ObjectMapper om = new ObjectMapper();

    private static final Cache<String, JSONObject> cache = CacheUtil.newTimedCache(3 * 60 * 60 * 1000);

    /**
     * 判断指定日期是否是节假日
     *
     * @return true-是；false-否
     */
    @RuleMethod
    public boolean isHoliday(Date date) {
        try {
            String dateStr = date2Str(date, "yyyyMMdd");
            JSONObject obj = cache.get(dateStr);
            if (obj != null && obj.containsKey("type")) {
                return obj.getIntValue("type") != 0;
            }
            String json = getReqUrl("https://www.mxnzp.com/api/holiday/single/" + dateStr + "?app_id=qwlyerngwkjtjoei&app_secret=MEg1bURxRmFmU2QvczlaNzdIdFozdz09");
            obj = JSON.parseObject(json);
            if (obj.getIntValue("code") == 1) {
                obj = obj.getJSONObject("data");
            }
            cache.put(dateStr, obj);
            //TODO 要不要根据周几（weekDay=6）来判断是否发送？
            return obj.getIntValue("type") != 0;
        } catch (Exception e) {
            log.error("调用isHoliday接口出错：" + e, e);
            return false;//失败的时候，就认为是非假期，不能影响工作嘛
        }
    }

    @RuleMethod
    public Date str2Date(Object date) {
        return str2PatternDate(date, "yyyy-MM-dd");
    }

    @RuleMethod
    private Date str2PatternDate(Object date, String pattern) {
        try {
            if (date == null) {
                return null;
            } else if (date instanceof Date) {
                return (Date) date;
            } else if (date instanceof LocalDate) {
                return Date.from(Instant.from((LocalDate) date));
            } else if (date instanceof LocalDateTime) {
                return Date.from(Instant.from((LocalDateTime) date));
            } else {
                return DateUtils.parseDate(date.toString(), pattern);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }


    /**
     * GET请求指定的url并返回内容
     *
     * @param url 指定的url
     * @return 返回响应内容
     */
    @RuleMethod
    public String getReqUrl(String url) {
        return HttpUtil.get(url, 10000);
    }

    @RuleMethod
    public Map json2Map(String json) {
        return JSON.parseObject(json, Feature.OrderedField);
    }

    @RuleMethod
    public List json2List(String json) {
        return JSON.parseObject(json, JSONArray.class, Feature.OrderedField);
    }

    /**
     * 从API平台中获取data数据，返回Map格式
     *
     * @param url
     * @return
     */
    @RuleMethod
    public Map readMapDataFromApi(String url) {
        String str = getReqUrl(url);
        JSONObject json = JSON.parseObject(str, Feature.OrderedField);
        String code = json.getString("code");

        if (!"0".equals(code)) {
            return null;
        }
        return json.getJSONObject("data");
    }

    /**
     * 从API平台中获取data数据，返回List格式
     *
     * @param url
     * @return
     */
    @RuleMethod
    public List readListDataFromApi(String url) {
        String str = getReqUrl(url);
        JSONObject json = JSON.parseObject(str, Feature.OrderedField);
        String code = json.getString("code");

        if (!"0".equals(code)) {
            return null;
        }
        return json.getJSONArray("data");
    }

    /**
     * 将map转换为字符串
     *
     * @param map            map对象
     * @param keyValueFormat key和value的组装形式，使用 $key 和 $value 代替对应的值
     * @return
     */
    @RuleMethod
    public String map2String(Map map, String keyValueFormat) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        StringBuilder ret = new StringBuilder();
        for (Object key : map.keySet()) {
            String val = map.get(key).toString();
            ret.append(keyValueFormat.replace("$key", key.toString()).replace("$value", val));
        }
        return ret.toString();
    }

    @RuleMethod
    public String date2Str(Date date, String format) {
        if (date == null || StringUtils.isBlank(format)) {
            return "";
        }
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 发送预警。在一定时间内不会重复发送。最终发送通知时，调用的是sendNotice方法
     */
    @RuleMethod
    public void sendAlarm(boolean hasAlarm, Long scheduleId, Long alarmInterval, String alarmMsg, String resumeMsg, String token) {
        scheduleJobDetail.sendAlarm(() -> hasAlarm, Integer.parseInt(ScheduleJobDetail.MONITOR_OTHER), scheduleId, ScheduleJobDetail.MonitorDimension.OTHER.getType(), alarmInterval, alarmMsg, resumeMsg, token);
    }

    /**
     * 发送消息到指定的群机器人
     *
     * @param notice
     * @param token
     */
    @RuleMethod
    public void sendNotice(String notice, String token) {
        if (StringUtils.isBlank(notice)) {
            return;
        }
        if (StringUtils.isBlank(token)) {
            throw new IllegalArgumentException("sendNotice need token！");
        }
        try {
            String url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + token.trim();
            HttpUtil.post(url, JSON.toJSONString(new WxworkRobotMsg(notice)).replace("\\\\n", "\n"), 3000);
        } catch (Exception e) {
            log.warn("发送预警信息失败：" + e, e);
        }
    }

    @Data
    static class WxworkRobotMsg {
        private String msgtype = "markdown";
        private MarkdownMsg markdown;

        public WxworkRobotMsg(String markdown) {
            this.markdown = new MarkdownMsg(markdown);
        }

    }

    @Data
    @AllArgsConstructor
    static class MarkdownMsg {
        private String content;
    }
}
